package org.microservice.gateway.config.route;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.microservice.common.entity.SysZuulRoute;
import org.microservice.common.util.constant.CacheConstant;
import org.microservice.common.util.constant.MqQueueConstant;
import org.microservice.redis.util.RedisService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.discovery.DiscoveryClientRouteLocator;

import java.util.*;

/**
 * @author lengleng
 * @date 2018/5/15
 * 动态路由实现
 */
@Slf4j
public class DynamicRouteLocator extends DiscoveryClientRouteLocator {
    private ZuulProperties properties;

    private RedisService redisService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public DynamicRouteLocator(String servletPath, DiscoveryClient discovery, ZuulProperties properties,
                               ServiceInstance localServiceInstance, RedisService redisService) {
        super(servletPath, discovery, properties, localServiceInstance);
        this.properties = properties;
        this.redisService = redisService;
    }

    /**
     * 重写路由配置
     * <p>
     * 1. properties 配置。
     * 2. eureka 默认配置。
     * 3. DB数据库配置。
     *
     * @return 路由表
     */
    @Override
    protected LinkedHashMap<String, ZuulProperties.ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();
        //读取properties配置、eureka默认配置
        routesMap.putAll(super.locateRoutes());
        routesMap.putAll(locateRoutesFromDb());
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.isNotBlank(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return routesMap;
    }

    /**
     * Redis中保存的，没有从upms拉去，避免启动链路依赖问题（取舍），网关依赖业务模块的问题
     *
     * @return
     */
    private Map<String, ZuulProperties.ZuulRoute> locateRoutesFromDb() {
        Map<String, ZuulProperties.ZuulRoute> routes = new LinkedHashMap<>();

        if(!redisService.exists(CacheConstant.ZUUL_ROUTE_KEY)){
            rabbitTemplate.convertAndSend(MqQueueConstant.ROUTE_CONFIG_CHANGE,"0");
        }
        Object obj = redisService.get(CacheConstant.ZUUL_ROUTE_KEY);
        if (obj == null) {
            log.error("缓存中没有找到路由信息");
            return routes;
        }

        List<SysZuulRoute> results = (List<SysZuulRoute>) obj;
        for (SysZuulRoute result : results) {
            if (StringUtils.isBlank(result.getPath()) && StringUtils.isBlank(result.getUrl())) {
                continue;
            }

            ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
            try {
                zuulRoute.setId(result.getServiceId());
                zuulRoute.setPath(result.getPath());
                zuulRoute.setServiceId(result.getServiceId());
                zuulRoute.setRetryable(result.isRetryable());
                zuulRoute.setStripPrefix(result.isStripPrefix());
                zuulRoute.setUrl(result.getUrl());
                List<String> sensitiveHeadersList =new ArrayList<>();
                if(result.getSensitiveheadersList() != null){
                    sensitiveHeadersList = Arrays.asList(result.getSensitiveheadersList().split(","));

                }
                if (sensitiveHeadersList != null) {
                    Set<String> sensitiveHeaderSet = new HashSet<>();
                    sensitiveHeadersList.forEach(sensitiveHeader -> sensitiveHeaderSet.add(sensitiveHeader));
                    zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
                    zuulRoute.setCustomSensitiveHeaders(true);
                }
            } catch (Exception e) {
                log.error("从数据库加载路由配置异常", e);
            }
            routes.put(zuulRoute.getPath(), zuulRoute);
        }
        return routes;
    }
}
